using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Collections.ObjectModel;

namespace Tetrazune
{
    /// <summary>
    /// Controls the rendering and updating of many Sparkplosions
    /// </summary>
    public class Sparkler : DrawableGameComponent
    {
        private static Texture2D sparkle = null;

        private Collection<Sparkplosion> sparkles = new Collection<Sparkplosion>();
        private SpriteBatch spb;

        public Sparkler(Game game)
            : base(game)
        {
        }

        public Collection<Sparkplosion> Sparkles { get { return sparkles; } }

        protected override void LoadContent()
        {
            base.LoadContent();
            spb = new SpriteBatch(Game.GraphicsDevice);
            if (sparkle == null)
                sparkle = Game.Content.Load<Texture2D>("sparkle");
        }
        public override void Draw(GameTime gameTime)
        {
            base.Draw(gameTime);
            if (Sparkles.Count <= 0) return;
            spb.Begin(SpriteBlendMode.AlphaBlend);
            foreach (Sparkplosion sp in Sparkles)
                sp.Draw(spb, sparkle);
            spb.End();
        }
        public override void Update(GameTime gameTime)
        {
            base.Update(gameTime);
            for (int i = 0; i < Sparkles.Count; i++)
                if (!Sparkles[i].Update(gameTime.ElapsedGameTime))
                    Sparkles.RemoveAt(i--);
        }
    }

    /// <summary>
    /// Animates a small explosion of sparkles in a cloud of awesome.  Specify
    /// the number of sparkles, the radius, and the length of time to animate.
    /// </summary>
    public class Sparkplosion
    {
        private static readonly Random Random = new Random();

        private Vector3[] sparkles; //r, theta, and a randomly-generated distance
        private int minRad, maxRad;
        private TimeSpan animTime;
        private Vector2 loc;
        private float pps; //Pixels per Second sparkles move
        private bool isAnimating = true;

        /// <summary>
        /// Initializes a new Sparkplosion!
        /// </summary>
        /// <param name="game">The game this component belongs to.</param>
        /// <param name="location">The origin of the impending awesome</param>
        /// <param name="sparkleCount">The number of sparkle textures to render</param>
        /// <param name="minRadius">The minimum distance in pixels the textures will travel</param>
        /// <param name="maxRadius">The maximum distance in pixels the textures will travel</param>
        /// <param name="animationTime">The time it should take to do the full animation</param>
        public Sparkplosion(Vector2 location, int sparkleCount, int minRadius,
            int maxRadius, TimeSpan animationTime)
        {
            sparkles = new Vector3[sparkleCount];
            minRad = minRadius;
            maxRad = maxRadius;
            animTime = animationTime;
            loc = new Vector2(location.X, location.Y);
            pps = maxRad / (float)animationTime.TotalSeconds;
            InitializeVectors();
        }

        public void Draw(SpriteBatch spb, Texture2D sparkleTex)
        {
            if (!isAnimating) return;
            foreach (Vector3 v in sparkles)
                if (v.X < v.Z)
                    spb.Draw(sparkleTex, loc + GetCartesian(v.X, v.Y), Color.White);
        }

        public bool Update(TimeSpan elapsedTime)
        {
            if (!isAnimating) return false;
            bool visible = false;
            float amt = (float)(pps * elapsedTime.TotalSeconds);
            for (int i = 0; i < sparkles.Length; i++)
                if (sparkles[i].X < sparkles[i].Z)
                {
                    sparkles[i].X += amt;
                    visible = true;
                }
            isAnimating = visible;
            return true;
        }

        /// <summary>
        /// Initializes all sparkles to radius 0, sets them at a random theta, 
        /// and sets their max distance randomly between minRad and maxRad
        /// </summary>
        protected void InitializeVectors()
        {
            for (int i = 0; i < sparkles.Length; i++)
            {
                sparkles[i] = new Vector3(
                    0,
                    (float)Random.NextDouble() * MathHelper.TwoPi,
                    MathHelper.Lerp(minRad, maxRad, (float)Random.NextDouble()));
            }
        }


        private static Vector2 GetCartesian(float radius, float theta)
        {
            Vector2 ret = new Vector2();
            ret.X = (float)(radius * Math.Cos(theta));
            ret.Y = (float)(radius * Math.Sin(theta));
            return ret;
        }
    }
}